#ifndef SURFACE_H
#define SURFACE_H

#include <coord.h>
#include <color.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>

typedef struct surface {
  coord_t size;
  color_t *buffer;
} surface_t;

/**
 * Checks if ( x0, y0 ) is inside surface pointed by 'sp'.
 */
#define INSIDE( sp, x0, y0 ) \
  ( ( (sp)->size.x > x0 ) && ( (sp)->size.y > (y0) ) )

/**
 * Checks if the given coord_t is inside the surface.
 */
#define INSIDE_COORD( sp, c ) INSIDE( (sp), (c).x, (c).y )

/**
 * Checks if the given rectangle is inside the surface.
 */
#define INSIDE_RECT( sp, r ) \
  ( INSIDE_COORD( (sp), (r).p0 ) && INSIDE_COORD( (sp), (r).p1 ) )

/**
 * Get pixel from surface
 */
#define PIXEL_AT( sp, x0, y0 ) \
  ( (sp)->buffer[ QUAD_TO_LIN( (sp)->size.x, (x0), (y0) ) ] )



surface_t *
surface_new( uint16_t width, uint16_t height );

void
surface_free( surface_t *surface );

void
surface_clear( const surface_t *surface );

void
surface_reset_visits( const surface_t *surface );

void
surface_fill( const surface_t *surface, color_t color, rect_t rect );


/**
 * Paint a pixel, consider transparency
 */
static inline void
pixel_paint( color_t *pixel, const color_t color, const float transp )
{
  /*
   * HACK:
   * We will use the still unused color_t.a field to set visited elements.
   */
  if ( pixel->a == 1 )
    return;

  if ( transp <= 0.0 )
    *pixel = color;
  else if ( transp < 1.0 )
    {
      pixel->r = (uint8_t)( ( pixel->r * ( transp ) ) +
			    ( color.r * ( 1 - transp ) ) );
      pixel->g = (uint8_t)( ( pixel->g * ( transp ) ) +
			    ( color.g * ( 1 - transp ) ) );
      pixel->b = (uint8_t)( ( pixel->b * ( transp ) ) +
			    ( color.b * ( 1 - transp ) ) );
    }
  pixel->a = 1;
}

/**
 * Draw pixel, take care to not draw over surface boundaries
 */
static inline void
surface_draw_pixel( const surface_t *surface,
		    const uint16_t x, const uint16_t y,
		    const color_t color, const float transp )
{
  assert( surface != NULL );
  if ( ( x >= surface->size.x ) || ( y >= surface->size.y ) )
    return;

  color_t *pixel = &PIXEL_AT( surface, x, y );
  pixel_paint( pixel, color, transp );
}



#endif /* SURFACE_H */
